import Module from './Module';
import $ from 'jquery';

export default class InputManager extends Module {

	_init() {
		let selectAllKey;
		let submitKey;
		this.editor = this._module;
		this.throttledValueChanged = this.editor.util.throttle(params => setTimeout(() => this.editor.trigger('valuechanged', params), 10), 300);
		this.throttledSelectionChanged = this.editor.util.throttle(() => this.editor.trigger('selectionchanged'), 50);
		$(document).on(`selectionchange.simditor${this.editor.id}`, () => {
			let triggerEvent;
			if (!(this.focused && !this.editor.clipboard.pasting)) return;

			triggerEvent = () => {
				if (this._selectionTimer) {
					clearTimeout(this._selectionTimer);
					this._selectionTimer = null;
				}
				if (this.editor.selection._selection.rangeCount > 0) {
					return this.throttledSelectionChanged();
				} else {
					return this._selectionTimer = setTimeout(() => {
						this._selectionTimer = null;
						if (this.focused) {
							return triggerEvent();
						}
					}, 10);
				}
			};
			return triggerEvent();
		});
		this.editor.on('valuechanged', () => {
			let $rootBlocks;
			this.lastCaretPosition = null;
			$rootBlocks = this.editor.body.children().filter((i, node) => this.editor.util.isBlockNode(node));
			if (this.focused && $rootBlocks.length === 0) {
				this.editor.selection.save();
				this.editor.formatter.format();
				this.editor.selection.restore();
			}
			this.editor.body.find('hr, pre, .simditor-table').each((i, el) => {
				let $el;
				let formatted;
				$el = $(el);
				if ($el.parent().is('blockquote') || $el.parent()[0] === this.editor.body[0]) {
					formatted = false;
					if ($el.next().length === 0) {
						$('<p/>').append(this.editor.util.phBr).insertAfter($el);
						formatted = true;
					}
					if ($el.prev().length === 0) {
						$('<p/>').append(this.editor.util.phBr).insertBefore($el);
						formatted = true;
					}
					if (formatted) {
						return this.throttledValueChanged();
					}
				}
			});
			this.editor.body.find('pre:empty').append(this.editor.util.phBr);
			if (!this.editor.util.support.onselectionchange && this.focused) {
				return this.throttledSelectionChanged();
			}
		});
		this.editor.body.on('keydown', $.proxy(this._onKeyDown, this)).on('keypress', $.proxy(this._onKeyPress, this)).on('keyup', $.proxy(this._onKeyUp, this)).on('mouseup', $.proxy(this._onMouseUp, this)).on('focus', $.proxy(this._onFocus, this)).on('blur', $.proxy(this._onBlur, this)).on('drop', $.proxy(this._onDrop, this)).on('input', $.proxy(this._onInput, this));
		if (this.editor.util.browser.firefox) {
			this.editor.hotkeys.add('cmd+left', e => {
				e.preventDefault();
				this.editor.selection._selection.modify('move', 'backward', 'lineboundary');
				return false;
			});
			this.editor.hotkeys.add('cmd+right', e => {
				e.preventDefault();
				this.editor.selection._selection.modify('move', 'forward', 'lineboundary');
				return false;
			});
			selectAllKey = this.editor.util.os.mac ? 'cmd+a' : 'ctrl+a';
			this.editor.hotkeys.add(selectAllKey, () => {
				let $children;
				let firstBlock;
				let lastBlock;
				let range;
				$children = this.editor.body.children();
				if (!($children.length > 0)) {
					return;
				}
				firstBlock = $children.first().get(0);
				lastBlock = $children.last().get(0);
				range = document.createRange();
				range.setStart(firstBlock, 0);
				range.setEnd(lastBlock, this.editor.util.getNodeLength(lastBlock));
				this.editor.selection.range(range);
				return false;
			});
		}
		submitKey = this.editor.util.os.mac ? 'cmd+enter' : 'ctrl+enter';
		return this.editor.hotkeys.add(submitKey, () => {
			this.editor.el.closest('form').find('button:submit').click();
			return false;
		});
	}

	_onFocus() {
		if (this.editor.clipboard.pasting) return;
		this.editor.el.addClass('focus').removeClass('error');
		this.focused = true;
		return setTimeout(() => {
			let range = this.editor.selection._selection.getRangeAt(0);
			if (range.startContainer === this.editor.body[0]) {
				if (this.lastCaretPosition) {
					this.editor.undoManager.caretPosition(this.lastCaretPosition);
				} else {
					range = document.createRange();
					this.editor.selection.setRangeAtStartOf(this.editor.body.children().first(), range);
				}
			}
			this.lastCaretPosition = null;
			this.editor.triggerHandler('focus');
			if (!this.editor.util.support.onselectionchange) return this.throttledSelectionChanged();
		}, 0);
	}

	_onBlur() {
		let ref;
		if (this.editor.clipboard.pasting) {
			return;
		}
		this.editor.el.removeClass('focus');
		this.editor.sync();
		this.focused = false;
		this.lastCaretPosition = (ref = this.editor.undoManager.currentState()) != null ? ref.caret : void 0;
		return this.editor.triggerHandler('blur');
	}

	_onMouseUp() {
		if (!this.editor.util.support.onselectionchange) {
			return this.throttledSelectionChanged();
		}
	}

	_onKeyDown(e) {
		if (this.editor.triggerHandler(e) === false) return false;
		if (this.editor.hotkeys.respondTo(e)) return;
		if (this.editor.keystroke.respondTo(e)) {
			this.throttledValueChanged();
			return false;
		}
		if (this._modifierKeys.indexOf(e.which) >= 0 || this._arrowKeys.indexOf(e.which) >= 0) return;
		if (this.editor.util.metaKey(e) && e.which === 86) return;
		if (!this.editor.util.support.oninput) this.throttledValueChanged(['typing']);
		return null;
	}

	_onKeyPress(e) {
		if (this.editor.triggerHandler(e) === false) return false;
	}

	_onKeyUp(e) {
		let ref;
		if (this.editor.triggerHandler(e) === false) 	return false;
		if (!this.editor.util.support.onselectionchange && (ref = e.which, this._arrowKeys.indexOf(ref) >= 0)) {
			this.throttledValueChanged();
			return;
		}
		if ((e.which === 8 || e.which === 46) && this.editor.util.isEmptyNode(this.editor.body)) {
			this.editor.body.empty();
			this.editor.selection.setRangeAtStartOf($('<p/>').append(this.editor.util.phBr).appendTo(this.editor.body));
		}
	}

	_onDrop(e) {
		if (this.editor.triggerHandler(e) === false) {
			return false;
		}
		return this.throttledValueChanged();
	}

	_onInput() {
		return this.throttledValueChanged(['oninput']);
	}
}

InputManager.pluginName = 'InputManager';
InputManager.prototype._modifierKeys = [16, 17, 18, 91, 93, 224];
InputManager.prototype._arrowKeys = [37, 38, 39, 40];